bugfix(skirmish): Set consistent seed values for skirmish games to prevent mismatches for restarted skirmish games#2270
Conversation
|
| Filename | Overview |
|---|---|
| Generals/Code/GameEngine/Source/GameClient/GUI/GUICallbacks/Menus/QuitMenu.cpp | Adds seed capture before clearGameData and reuses it for skirmish restarts. Logic is sound — TheSkirmishGameInfo survives clearGameData(FALSE) and the seed is correctly captured early. One pre-existing signed/unsigned mismatch in type (Int getSeed → UnsignedInt seed) is harmless in practice. |
| GeneralsMD/Code/GameEngine/Source/GameClient/GUI/GUICallbacks/Menus/QuitMenu.cpp | Mirror of the Generals/ changes. Seed is captured before clearGameData, assert guards the TheSkirmishGameInfo/gameMode invariant, and InitRandom(seed) replaces the hardcoded 0. Same signed/unsigned type mismatch (Int getSeed → UnsignedInt seed) as Generals variant, harmless in practice. |
| Generals/Code/GameEngine/Source/GameClient/GUI/GUICallbacks/Menus/SkirmishGameOptionsMenu.cpp | Moves InitGameLogicRandom call to inside the isSkirmish/else branches so it is correctly called with the actual seed for skirmish maps and with 0 for single-player maps. Clean and correct change. |
| GeneralsMD/Code/GameEngine/Source/GameClient/GUI/GUICallbacks/Menus/SkirmishGameOptionsMenu.cpp | Mirror of Generals/ changes. InitGameLogicRandom correctly moved inside the isSkirmish branch (with actual seed) and else branch (with 0). No issues found. |
Sequence Diagram
sequenceDiagram
participant User
participant QuitMenu
participant TheSkirmishGameInfo
participant TheGameLogic
participant InitRandom
Note over User,InitRandom: Initial skirmish game start (SkirmishGameOptionsMenu)
User->>TheSkirmishGameInfo: setSeed(GetTickCount())
User->>TheSkirmishGameInfo: startGame(0)
alt isSkirmish == TRUE
TheSkirmishGameInfo-->>QuitMenu: getSeed()
QuitMenu->>InitRandom: InitGameLogicRandom(seed)
else isSkirmish == FALSE (solo map)
QuitMenu->>InitRandom: InitGameLogicRandom(0)
end
Note over User,InitRandom: Restarting skirmish game (QuitMenu - restartMissionMenu)
User->>QuitMenu: Click Restart
QuitMenu->>TheGameLogic: getGameMode()
TheGameLogic-->>QuitMenu: gameMode (e.g. GAME_SKIRMISH)
QuitMenu->>TheSkirmishGameInfo: getSeed() [captured BEFORE clearGameData]
TheSkirmishGameInfo-->>QuitMenu: seed
QuitMenu->>TheGameLogic: clearGameData(FALSE)
Note over QuitMenu: TheSkirmishGameInfo survives clearGameData
alt replayFile is empty (new game)
QuitMenu->>InitRandom: InitRandom(seed) [skirmish: reuses original seed]
else replayFile not empty (replay)
QuitMenu->>QuitMenu: TheRecorder->playbackFile(replayFile)
end
Last reviewed commit: 00bddf4
Generals/Code/GameEngine/Source/GameClient/GUI/GUICallbacks/Menus/QuitMenu.cpp
Outdated
Show resolved
Hide resolved
Generals/Code/GameEngine/Source/GameClient/GUI/GUICallbacks/Menus/QuitMenu.cpp
Outdated
Show resolved
Hide resolved
GeneralsMD/Code/GameEngine/Source/GameClient/GUI/GUICallbacks/Menus/QuitMenu.cpp
Outdated
Show resolved
Hide resolved
GeneralsMD/Code/GameEngine/Source/GameClient/GUI/GUICallbacks/Menus/QuitMenu.cpp
Outdated
Show resolved
Hide resolved
Generals/Code/GameEngine/Source/GameClient/GUI/GUICallbacks/Menus/QuitMenu.cpp
Outdated
Show resolved
Hide resolved
Generals/Code/GameEngine/Source/GameClient/GUI/GUICallbacks/Menus/QuitMenu.cpp
Outdated
Show resolved
Hide resolved
|
I did find a single case where the game would start a new |
6dacb8a to
45fa3ea
Compare
|
EDIT: Maybe I didn't properly explain what I documented here. The findings below explain how the seed value is set for different game modes. I noted the execution flow with the current changes of this PR. Here are the results of my testing with this PR: 1. Campaign ( 2. Challenges ( 3. Skirmish, single player map / scenario ( 4. Skirmish, multiplayer map ( |
|
If we ever to enable replays for campaign / challenge / single player scenarios, we may need to verify that this issue doesn't happen there as well. I don't see anything that could still present an issue in that regard, though. |
GeneralsMD/Code/GameEngine/Source/GameClient/GUI/GUICallbacks/Menus/SkirmishGameOptionsMenu.cpp
Show resolved
Hide resolved
GeneralsMD/Code/GameEngine/Source/GameClient/GUI/GUICallbacks/Menus/QuitMenu.cpp
Show resolved
Hide resolved
GeneralsMD/Code/GameEngine/Source/GameClient/GUI/GUICallbacks/Menus/QuitMenu.cpp
Outdated
Show resolved
Hide resolved
GeneralsMD/Code/GameEngine/Source/GameClient/GUI/GUICallbacks/Menus/QuitMenu.cpp
Outdated
Show resolved
Hide resolved
3208aa9 to
4b6d3dc
Compare
GeneralsMD/Code/GameEngine/Source/GameClient/GUI/GUICallbacks/Menus/QuitMenu.cpp
Outdated
Show resolved
Hide resolved
GeneralsMD/Code/GameEngine/Source/GameClient/GUI/GUICallbacks/Menus/QuitMenu.cpp
Outdated
Show resolved
Hide resolved
GeneralsMD/Code/GameEngine/Source/GameClient/GUI/GUICallbacks/Menus/QuitMenu.cpp
Show resolved
Hide resolved
GeneralsMD/Code/GameEngine/Source/GameClient/GUI/GUICallbacks/Menus/QuitMenu.cpp
Outdated
Show resolved
Hide resolved
GeneralsMD/Code/GameEngine/Source/GameClient/GUI/GUICallbacks/Menus/QuitMenu.cpp
Show resolved
Hide resolved
|
I expect to update this PR in a couple of days. |
GeneralsMD/Code/GameEngine/Source/GameClient/GUI/GUICallbacks/Menus/QuitMenu.cpp
Show resolved
Hide resolved
5a53659 to
096d621
Compare
|
Replicated in Generals, and ready to be merged, I think. |
Generals/Code/GameEngine/Source/GameClient/GUI/GUICallbacks/Menus/QuitMenu.cpp
Show resolved
Hide resolved
| // TheSuperHackers @bugfix Caball009 07/02/2026 Reuse the previous seed value for the new skirmish match to prevent mismatches. | ||
| // Campaign, challenge, and skirmish single-player scenarios all use GAME_SINGLE_PLAYER and are expected to use 0 as seed value. | ||
| DEBUG_ASSERTCRASH((TheSkirmishGameInfo != nullptr) == (gameMode == GAME_SKIRMISH), ("Unexpected game mode on map / mission restart")); | ||
| const UnsignedInt seed = TheSkirmishGameInfo ? TheSkirmishGameInfo->getSeed() : 0; |
There was a problem hiding this comment.
Signed-to-unsigned implicit conversion on seed
Same as in Generals/: GameInfo::getSeed() returns Int (signed), but seed is declared as const UnsignedInt. This creates an implicit signed-to-unsigned conversion. Consider declaring seed as Int to match the return type of getSeed().
| // TheSuperHackers @bugfix Caball009 07/02/2026 Reuse the previous seed value for the new skirmish match to prevent mismatches. | |
| // Campaign, challenge, and skirmish single-player scenarios all use GAME_SINGLE_PLAYER and are expected to use 0 as seed value. | |
| DEBUG_ASSERTCRASH((TheSkirmishGameInfo != nullptr) == (gameMode == GAME_SKIRMISH), ("Unexpected game mode on map / mission restart")); | |
| const UnsignedInt seed = TheSkirmishGameInfo ? TheSkirmishGameInfo->getSeed() : 0; | |
| const Int seed = TheSkirmishGameInfo ? TheSkirmishGameInfo->getSeed() : 0; |
Context Used: Rule from dashboard - Use nullptr instead of NULL for null pointer literals in C++ code (source)
Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!
Prompt To Fix With AI
This is a comment left during a code review.
Path: GeneralsMD/Code/GameEngine/Source/GameClient/GUI/GUICallbacks/Menus/QuitMenu.cpp
Line: 203:206
Comment:
**Signed-to-unsigned implicit conversion on seed**
Same as in `Generals/`: `GameInfo::getSeed()` returns `Int` (signed), but `seed` is declared as `const UnsignedInt`. This creates an implicit signed-to-unsigned conversion. Consider declaring `seed` as `Int` to match the return type of `getSeed()`.
```suggestion
const Int seed = TheSkirmishGameInfo ? TheSkirmishGameInfo->getSeed() : 0;
```
**Context Used:** Rule from `dashboard` - Use nullptr instead of NULL for null pointer literals in C++ code ([source](https://app.greptile.com/review/custom-context?memory=c69cf1a9-c69a-4330-a013-69bb5d6701da))
<sub>Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!</sub>
How can I resolve this? If you propose a fix, please make it concise.There was a problem hiding this comment.
I could do static_cast<UnsignedInt>(TheSkirmishGameInfo ? TheSkirmishGameInfo->getSeed() : 0) to make the conversion explicit.
This PR makes the seed value consistent for started vs. restarted skirmish games, and fixes a bug that causes replays of restarted skirmish game to always mismatch.
TODO: